home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Amiga Tools 3
/
Amiga Tools 3.iso
/
grafik
/
raytracing
/
rayshade-4.0.6.3
/
inetray
/
rpc.inetrayd.c
< prev
next >
Wrap
C/C++ Source or Header
|
1993-08-19
|
16KB
|
654 lines
/*======================================================================
R P C . I N E T R A Y D . C
doc: Mon Feb 24 16:24:35 1992
dlm: Thu Aug 19 23:08:22 1993
(c) 1992 ant@julia
uE-Info: 430 24 T 0 0 72 10 2 8 ofnI
======================================================================*/
/*#define VERBOSE /* babble */
/*#define TRACEWORKERS /* trace worker pids */
#include <string.h> /* The long and sad inclusion story */
#include <signal.h>
#include <netdb.h> /* Prefer system over rpc/netdb.h */
#include <stdio.h>
#include <pwd.h>
#include <errno.h>
#include <syslog.h>
#include <sys/file.h> /* A/UX wants that */
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/param.h>
#include <sys/wait.h>
#ifndef INADDR_ANY
#include <netinet/in.h>
#endif
#include <rpc/rpc.h>
#include "rayshade.h"
#include "picture.h"
#include "version.h"
#include "patchlevel.h"
#include "inetray.h"
#include "config.h"
#include "common.h"
#include "irtrace.h"
#include "utils.h"
#include "lbuffer.h"
#include "stderr.h"
#define MAXARGS 256 /* max # of args allowed */
#define ARGBUFSZE 8192 /* max buffer for args */
extern int errno; /* for connection retry */
extern void inetray_1(); /* generated dispatch routine */
EXPORT int _rpcpmstart; /* Started by a port monitor ? */
static int argc; /* argcount */
static char *argv[MAXARGS]; /* argvector */
static char argbuf[ARGBUFSZE]; /* buffer for argv */
static int pid = -1; /* pid of child */
static int bufPid = -1; /* pid of lBuffer */
static char rName[MAXHOSTNAMELEN]; /* remote hostname */
static int lSize; /* size of scanline */
static int sock = -1; /* result socket */
static XDR xdrs; /* result XDR stream */
static int key; /* session key */
static u_long progNum; /* program number (INETRAY + wid) */
static uid_t uid; /* user id (ideal) */
static int bufPipe[2]; /* pipe from live buffer */
static char initialized = FALSE; /* files read */
static int firstFrame; /* deferred startframe number */
static char bufReadingSock = FALSE; /* live buffer is reading socket */
static int rpcSock,proto; /* socket & proto to register */
static SVCXPRT *transport; /* transport handle */
static int bNr = -1; /* bNr of last request */
/*----------------------------------------------------------------------*/
static void parseQuote(s,spp,bpp) /* parse quoted arg */
char s[]; int *spp,*bpp;
{
argv[argc] = &argbuf[*bpp];
(*spp)++;
while (s[*spp] != '\'') { /* copy simply */
argbuf[(*bpp)++] = s[(*spp)++];
}
argbuf[(*bpp)++] = '\0';
(*spp)++; /* skip quote char */
}
static void parseArgs(s) /* break up s into argv */
char s[];
{
int bufp,sp,sl;
argc = bufp = sp = 0;
sl = strlen(s);
while (sp < sl) {
if (s[sp] != '\'') {
sp++;
continue;
}
parseQuote(s,&sp,&bufp);
argc++;
}
argv[argc] = NULL;
}
static void exitClean(s) /* kill & exit */
int s;
{
#ifdef VERBOSE
SYSLOG(LOG_NOTICE,"exitClean(%d)",s);
#endif
if (pid > 0) kill(pid,SIGKILL);
if (!_rpcpmstart)
(void)pmap_unset(progNum,IRV1);
CLOSELOG();
closeStderr();
exit(s);
}
/*----------------------------------------------------------------------*/
static void checkAbort() /* abort on crash */
{
fd_set selRead;
int status;
signal(SIGALRM,checkAbort); /* sysV yummy dummy */
#ifdef VERBOSE
SYSLOG(LOG_NOTICE,"Checking for abort");
#endif
if (pid > 0) { /* check child exit stat */
#ifdef VERBOSE
SYSLOG(LOG_NOTICE,"Checking for child termination");
#endif
if (waitpid(pid,&status,WNOHANG) > 0) {
pid = 0;
if (status != 0) {
SYSLOG(LOG_ERR,"Abort: worker exit status %d",status);
exitClean(1);
}
}
}
if (sock == -1) { /* not yet set up */
SYSLOG(LOG_ERR,"Lost INIT request");
exitClean(1);
}
#ifdef VERBOSE
SYSLOG(LOG_NOTICE,"Checking socket");
#endif
if (bufReadingSock) { /* watch out! */
FD_ZERO(&selRead);
FD_SET(bufPipe[IN],&selRead); /* check buffer pipe */
if (select(bufPipe[IN]+1,&selRead,NULL,NULL,&now) < 0) {
SYSLOG(LOG_ERR,"select(): %m");
exitClean(1);
}
bufReadingSock = !FD_ISSET(bufPipe[IN],&selRead);
}
if (bufReadingSock) return; /* really reading -> wait */
FD_ZERO(&selRead); /* check connection */
FD_SET(sock,&selRead);
if (select(sock+1,&selRead,NULL,NULL,&now) < 0) {
SYSLOG(LOG_ERR,"select(): %m");
exitClean(1);
}
if (FD_ISSET(sock,&selRead)) { /* read() would return 0 */
SYSLOG(LOG_ERR,"Dispatcher disappeared");
exitClean(1);
}
}
static void setupTimer()
{
struct itimerval chkClntT;
#ifdef VERBOSE
SYSLOG(LOG_NOTICE,"setupTimer()");
#endif
chkClntT.it_interval.tv_sec = chkClntT.it_value.tv_sec = CHKCLNT;
chkClntT.it_interval.tv_usec = chkClntT.it_value.tv_usec = 0;
signal(SIGALRM,checkAbort);
if (setitimer(ITIMER_REAL,&chkClntT,NULL) < 0) {
SYSLOG(LOG_ERR,"setitimer: %m");
exitClean(1);
}
}
static void registerSelf() /* register self */
{
transport = svcudp_create(rpcSock);
if (transport == NULL) {
SYSLOG(LOG_ERR,"cannot create udp service.");
exitClean(1);
}
if (!svc_register(transport,progNum,IRV1,inetray_1,proto)) {
SYSLOG(LOG_ERR,"unable to register (%d,VER,udp)",progNum);
exitClean(1);
}
#ifdef VERBOSE
SYSLOG(LOG_NOTICE,"Opening Stderr");
#endif
if (openStderr("rpc.inetrayd") < 0) exitClean(1);
}
static void slaveSvcs(n) /* start secondary servers */
int n; /* clean up & register */
{
int pid,thisProg;
thisProg = progNum;
while (n-- > 0) { /* start n */
thisProg++;
pid = fork();
if (pid < 0) {
SYSLOG(LOG_ERR,"fork: %m");
exitClean(1);
}
if (pid == 0) { /* new server */
progNum = thisProg;
svc_destroy(transport);
(void)pmap_unset(progNum,IRV1);
_rpcpmstart = FALSE;
rpcSock = RPC_ANYSOCK;
proto = IPPROTO_UDP;
registerSelf();
setupTimer();
#ifdef VERBOSE
SYSLOG(LOG_NOTICE,"INIT: forked prog # %d",progNum);
#endif
return;
}
}
}
/*----------------------------------------------------------------------*/
static void killSelf() /* received SIGINT(kill) signal */
{
if (!xdrrec_endofrecord(&xdrs,TRUE)) {
SYSLOG(LOG_ERR,"xdrrec_endofrecord() failed");
exitClean(1);
}
exit(0);
}
/*----------------------------------------------------------------------*/
static writeit(dummy,buf,nbyte) /* XDR write routine */
char *dummy,*buf; int nbyte;
{
int writ;
writ = write(sock,buf,nbyte);
if (writ < 0) SYSLOG(LOG_ERR,"XDR write: %m");
return writ;
}
static void sendResult(bNr,bSz,block,skip) /* send whole resultblock back */
int bNr,bSz; Scanline *block; int skip;
{
pixArr res;
int i;
bNr += skip;
if (!xdr_int(&xdrs,&bNr)) {
SYSLOG(LOG_ERR,"xdr_int() failed");
exitClean(1);
}
res.pixArr_len = lSize;
for (i=skip*bSz+1; i<=(skip+1)*bSz; i++) {
res.pixArr_val = (xdrPix *)block[i].pix;
if (!xdr_pixArr(&xdrs,&res)) {
SYSLOG(LOG_ERR,"xdr_pixArr() failed");
exitClean(1);
}
}
if (!xdrrec_endofrecord(&xdrs,TRUE)) {
SYSLOG(LOG_ERR,"xdrrec_endofrecord() failed");
exitClean(1);
}
}
/*----------------------------------------------------------------------*/
void *init_1(param) /* init self */
iPrm *param;
{
int wid,wpid;
char wd[MAXPATHLEN],v[8],*cp,*getcwd();
struct passwd *p;
struct hostent *host;
struct sockaddr_in name;
#ifdef VERBOSE
SYSLOG(LOG_NOTICE,"INIT:");
#endif
if (pid != -1) /* only once */
return (void *)NULL;
pid = 0; /* initialized */
slaveSvcs(param->nSvcs-1); /* start 2nd svcs */
signal(SIGINT,SIG_IGN); /* ignore kill signal */
strncpy(rName,param->rName,MAXHOSTNAMELEN);
key = param->key; /* session key */
if (uid == 0) { /* set default uid */
if (setuid(param->uid) < 0) {
SYSLOG(LOG_NOTICE,"setuid: %m");
}
uid = geteuid(); /* get effective uid */
if (uid == 0) {
SYSLOG(LOG_ERR,"can't run as root");
exitClean(1);
}
}
p = getpwuid(uid); /* get user info */
if (p == NULL) {
SYSLOG(LOG_ERR,"illegal user id %d",uid);
exitClean(1);
}
addHome(uid,param->cwd,wd); /* get right dir */
if (chdir(wd) < 0) { /* try to get there */
SYSLOG(LOG_NOTICE,"WARNING: chdir(%s): %m",wd);
}
if (key != 0) { /* only pinged */
parseArgs(param->cmdLine);
}
/* init socket */
if ((host = gethostbyname(rName)) == NULL) {
SYSLOG(LOG_ERR,"gethostbyname(%s) failed!",rName);
exitClean(1);
}
name.sin_family = AF_INET;
name.sin_port = htons(param->rPort);
memcpy((char *)&name.sin_addr,host->h_addr_list[0],host->h_length);
if ((sock = socket(PF_INET,SOCK_STREAM,0)) < 0) {
SYSLOG(LOG_ERR,"socket: %m");
exitClean(1);
}
if (connect(sock,&name,sizeof(name)) < 0) {
if (errno == ECONNREFUSED) { /* retry once */
close(sock);
sleep((rand()%2)+1); /* wait random time */
if ((sock = socket(PF_INET,SOCK_STREAM,0)) < 0) {
SYSLOG(LOG_ERR,"socket: %m");
exitClean(1);
}
if (connect(sock,&name,sizeof(name)) < 0) {
SYSLOG(LOG_ERR,"connect: %m");
exitClean(1);
}
} else {
SYSLOG(LOG_ERR,"connect: %m");
exitClean(1);
}
}
xdrrec_create(&xdrs,0,0,NULL,NULL,writeit); /* create XDR */
xdrs.x_op = XDR_ENCODE;
wid = progNum - INETRAY; /* send back info */
if (!xdr_int(&xdrs,&wid)) { /* worker id */
SYSLOG(LOG_ERR,"xdr_int() failed");
exitClean(1);
}
wpid = getpid();
if (!xdr_int(&xdrs,&wpid)) { /* pid */
SYSLOG(LOG_ERR,"xdr_int() failed");
exitClean(1);
}
cp = p->pw_name; /* user name */
if (!xdr_string(&xdrs,&cp,32)) {
SYSLOG(LOG_ERR,"xdr_string() failed");
exitClean(1);
}
getcwd(wd,MAXPATHLEN); /* working dir */
stripHead(STRIPHEAD,wd);
stripHome(uid,wd);
cp = wd;
if (!xdr_string(&xdrs,&cp,MAXPATHLEN)) {
SYSLOG(LOG_ERR,"xdr_string() failed");
exitClean(1);
}
sprintf(v,"%s%d",VERSION,PATCHLEVEL); /* version check */
cp = v;
if (!xdr_string(&xdrs,&cp,8)) {
SYSLOG(LOG_ERR,"xdr_string() failed");
exitClean(1);
}
if (!xdrrec_endofrecord(&xdrs,TRUE)) {
SYSLOG(LOG_ERR,"xdrrec_endofrecord() failed");
exitClean(1);
}
if (param->sendIn) { /* receive file */
if (pipe(bufPipe) < 0) {
SYSLOG(LOG_ERR,"pipe: %m");
exitClean(1);
}
bufReadingSock = TRUE; /* buffer is reading */
bufPid = lPostBuffer(sock,bufPipe);
}
#ifdef VERBOSE
SYSLOG(LOG_NOTICE,"INIT done");
#endif
return (void *)NULL; /* dont reply rpc */
}
int *wait_1(keyP) /* wait 4 worker 2 die */
int *keyP;
{
int status,dPid;
static int res = 0;
#ifdef VERBOSE
SYSLOG(LOG_NOTICE,"WAITING FOR: %d",pid);
#endif
if (pid < 0) exit(0); /* not initialized */
if (*keyP != key) { /* authorize */
return (int *)NULL;
}
if (pid > 0) { /* one has been started */
reStartWait:
if ((dPid = waitpid(pid,&status,0)) < 0) { /* wait for it */
if (errno == EINTR) goto reStartWait;
SYSLOG(LOG_ERR,"wait: %m");
exitClean(1);
}
if (status != 0) {
SYSLOG(LOG_NOTICE,"worker exit status %d",status);
}
if (dPid != pid) { /* what happened ? */
kill(pid,SIGKILL); /* abort ! */
SYSLOG(LOG_ERR,"pid of dead %d instead of %d",dPid,pid);
exitClean(1);
}
#ifdef VERBOSE
SYSLOG(LOG_NOTICE,"pid %d returned %d",dPid,status);
#endif
pid = 0;
}
#ifdef VERBOSE
SYSLOG(LOG_NOTICE,"WAITING done");
#endif
return &res;
}
int *startframe_1(param) /* start new frame */
sfPrm *param;
{
static int res = 0;
int status;
#ifdef VERBOSE
SYSLOG(LOG_NOTICE,"STARTFRAME:");
#endif
if (pid < 0) exit(0); /* not initialized */
if (param->key != key) { /* authorize */
return (int *)NULL;
}
wait_1(&(param->key));
if (initialized) /* start new frame */
RSStartFrame(param->fNr);
else /* defer */
firstFrame = param->fNr;
bNr = -1; /* clear saved block# */
#ifdef VERBOSE
SYSLOG(LOG_NOTICE,"STARTFRAME done");
#endif
return &res;
}
void *traceblock_1(param) /* trace block of lines */
tbPrm *param;
{
int pgrp,status,saveIn,i;
Scanline *resBlock,*Raytrace();
#ifdef VERBOSE
SYSLOG(LOG_NOTICE,"TRACEBLOCK msg received");
#endif
if (pid < 0) exit(0); /* not initialized */
if (param->key != key) /* authorize */
return (void *)NULL;
if (bNr == param->bNr) /* message resent */
return (void *)NULL;
#ifdef VERBOSE
SYSLOG(LOG_NOTICE,"TRACEBLOCK started");
#endif
bNr = param->bNr; /* avoid doublework */
if (!initialized) { /* deferred stuff */
#ifdef VERBOSE
SYSLOG(LOG_NOTICE,"initializing");
#endif
if (bufPid > 0) { /* buffered stdin */
saveIn = dup(IN);
close(IN);
dup(bufPipe[IN]);
close(bufPipe[IN]);
}
lSize = RaytraceInit(argc,argv);
if (bufPid > 0) { /* restore stdin */
waitpid(bufPid,NULL,0);
bufPid = -1;
bufReadingSock = FALSE;
close(IN);
dup(saveIn);
}
RSStartFrame(firstFrame);
initialized = TRUE;
/* wait(NULL); /* get status */
}
wait_1(&(param->key));
pid = fork(); /* make new */
if (pid < 0) {
SYSLOG(LOG_ERR,"fork: %m");
exitClean(1);
}
if (pid == 0) { /* child */
nice(NICEDAEMON); /* run nicely */
signal(SIGINT,killSelf);
resBlock = Raytrace(param->nBlocks*param->bSz,
param->lNr);
signal(SIGINT,SIG_IGN);
for (i=0; i<param->nBlocks; i++)
sendResult(param->bNr,
param->bSz,
resBlock,i);
#ifdef VERBOSE
SYSLOG(LOG_NOTICE,"> EXIT");
#endif
exit(0);
}
#ifdef TRACEWORKERS
SYSLOG(LOG_NOTICE,"pid %d forked",pid);
#endif
#ifdef VERBOSE
SYSLOG(LOG_NOTICE,"pid %d forked",pid);
#endif
return NULL; /* don't block */
}
int *kill_1(keyP) /* kill worker */
int *keyP;
{
static int res = 0;
#ifdef VERBOSE
SYSLOG(LOG_NOTICE,"KILLING: %d",pid);
#endif
if (pid < 0) exit(0); /* not initialized */
if (*keyP != key) { /* authorize */
return (int *)NULL;
}
if (pid > 0) (void)kill(pid,SIGINT);
return &res;
}
void *terminate_1(keyP) /* terminate */
int *keyP;
{
#ifdef VERBOSE
SYSLOG(LOG_NOTICE,"TERMINATE:");
#endif
if (pid < 0) exit(0); /* not initialized */
if (*keyP != key) { /* authorize */
return;
}
if (pid > 0) { /* force */
kill(pid,SIGKILL);
wait_1(keyP);
}
if (bufPid > 0)
kill(bufPid,SIGKILL);
#ifdef VERBOSE
SYSLOG(LOG_NOTICE,"TERMINATE done");
#endif
/* if (progNum == INETRAY) /* wid == 0 */
/* CLOSELOG();*/
exitClean(0);
}
/*======================================================================*/
int _rpcfdtype = SOCK_DGRAM; /* Whether Stream or Datagram ? */
main(ac,av)
int ac; char *av[];
{
struct sockaddr_in saddr;
int asize = sizeof(saddr);
int ssize = sizeof(int);
int fd;
_rpcpmstart = (ac == 1); /* logging */
if (!_rpcpmstart) CLOSELOG();
OPENLOG("rpc.inetrayd");
#ifdef VERBOSE
SYSLOG(LOG_NOTICE,"started!");
#endif
setupTimer();
#ifdef VERBOSE
SYSLOG(LOG_NOTICE,"Timer set up");
#endif
if (_rpcpmstart) { /* inetd */
rpcSock = 0;
proto = 0;
if (getsockname(rpcSock, (struct sockaddr *)&saddr, &asize) < 0) {
SYSLOG(LOG_ERR,"socket: %m");
exitClean(1);
}
if (saddr.sin_family != AF_INET) {
SYSLOG(LOG_ERR,"illegal protocol");
exitClean(1);
}
if (getsockopt(0, SOL_SOCKET, SO_TYPE,
(char *)&_rpcfdtype, &ssize) == -1) {
SYSLOG(LOG_ERR,"getsockopt: %m");
exitClean(1);
}
} else { /* inetray.starter */
(void)pmap_unset(INETRAY,IRV1);
rpcSock = RPC_ANYSOCK;
proto = IPPROTO_UDP;
}
#ifdef VERBOSE
SYSLOG(LOG_NOTICE,"trying to register self...");
#endif
uid = geteuid(); /* set up */
progNum = INETRAY;
registerSelf();
#ifdef VERBOSE
SYSLOG(LOG_NOTICE,"waiting for request...");
#endif
svc_run();
SYSLOG(LOG_ERR,"svc_run returned");
exitClean(1);
/* NOTREACHED */
}